<?php
/**
 * ActivityCalendar.class.php
 *
 * PHP version 5
 *
 * Copyright (c) Leo Valen  http://www.leovalen.no
 * All rights reserved.
 *
 * @author		Leo Valen <leo@code.coop>
 * @author      Martin Sommervold <martin.sommervold@ntnu.no>
 */
namespace TeamPlayers;
require 'iCalcreator.class.php';
require_once 'lib/Swift-4.0.6/lib/swift_required.php';
/**
 * Class for interacting with TeamPlayers Sharepoint calendars.
 *
 * @version		1.0
 */
class ActivityCalendar
{
	/**
	 * Array of calendar names => Sharepoint calendar RSS feed URLs
	 *
	 * @var string
	 * @access public
	 */
	public $calendars;
	/**
	 * Activities loaded from table
	 *
	 * @var array
	 * @access public
	 */
	public $activities;
	/**
	 * Interval between updating calendar data
	 *
	 * @var array
	 * @access public
	 */
	public $expiry;
	/**
	 * Mysql connection
	 *
	 * @var array
	 * @access protected
	 */
	protected $mysqli;
	/**
	 * Constructor
	 *
	 * @return		void
	 * @access		public
	 */
	public function __construct()
	{
	    $this->activities = array();
	    $this->expiry = 600;
	    /*
	     * Fetch calendar names and URLs
	     */
	    if ( $rows = TeamPlayers::$db->selectAssoc( "SELECT `name`, `feedURL` FROM `ActivityCalendarCalendars` ORDER BY `name` ASC" ) )
	    {
	        foreach ( $rows as $row )
	        {
	            $this->calendars[$row['name']] = $row['feedURL'];
	        }
	    }
	    /*
	     * Assign calendar names to Smarty
	     */
	    TeamPlayers::$smarty->assign( 'calendarNames', $this->getCalendarNames() );
	    /*
	     * Check for event creation request
	     */
	    $this->eventCreationRequest();
	    /*
	     * Check for event creation form request
	     */
	    $this->eventCreationFormRequest();
	    /*
	     * Check if this is a calendar entry search request and handle it
	     */
	    $this->searchRequest();
	}
	/**
	 * Parses calendar RSS feeds
	 *
	 * @param		bool $force   If set to true, feeds are fetched and parsed regardless of cache validity
	 * @return		bool          False on failure
	 * @access		public
	 */
	public function parseFeeds( $force = false )
	{
	    /*
	     * Check whether currently cached activity records have expired
	     */
	    $sql = "SELECT UNIX_TIMESTAMP( MAX( `timestamp` ) ) AS `max` FROM `ActivityCalendarSharepointRecords`";
	    if ( $result = TeamPlayers::$db->query( $sql ) )
	    {
	        $row = $result->fetch_assoc();
	        if ( time() < $row['max'] + $this->expiry && $force == false )
	        {
	            /*
	             * Cache is still valid
	             */
	            return true;
	        }
	    }
	    $activities = array();
        foreach ( $this->calendars as $name => $url )
        {
    		/*
    		 * Load RSS feed
    		 */
    		$xml = simplexml_load_file( $url );
    		/*
    		 * Check if feed was successfully parsed
    		 */
    		if ( ! is_object( $xml ) )
    		{
    		    return false;
    		}
    		/*
    		    Filter out relevant information from the feed
    		    
    			Note: The sharepoint supplied data is well formed, but has poor structure. As a result, this function has to compensate with a few "text hacks"
    			and is therefore very specific to this sharepoint stream, which is based of an outlook calendar.
    		*/
    		foreach ( $xml->channel->item as $item )
    		{
    		    $activity = array( 'calendar' => $name, 'title' => '', 'lab' => '', 'rig' => '', 'incharge' => '', 'start' => array(), 'end' => array() );
    			
    			// Filtering out start/end time from the XML CDATA
    			$startRegex = '#<div><b>Start Time:</b> ((([0-9]{2})\.([0-9]{2})\.([0-9]{4}) ([0-9]{2}):([0-9]{2}))?)</div>#';
    			$endRegex = '#<div><b>End Time:</b> ((([0-9]{2})\.([0-9]{2})\.([0-9]{4}) ([0-9]{2}):([0-9]{2}))?)</div>#';
    		
    			preg_match($startRegex, $item->description, $start);
    			preg_match($endRegex, $item->description, $end);
    			/*
    			 * The do/while loop splits activities spanning more than one day into one record for each day
    			 */
    			$currentTime = mktime( $start[6], $start[7], 0, $start[4], $start[3], $start[5] );
    			$endTime = mktime( $end[6], $end[7], 0, $end[4], $end[3], $end[5] );
    			do
    			{
    			    $year = date( 'Y', $currentTime );
    			    $month = date( 'm', $currentTime );
    			    $day = date( 'd', $currentTime );
        			$activity['start'] = array();
        			$activity['end'] = array();
        			$activity['start']['timestamp'] = mktime( $start[6], $start[7], 0, $month, $day, $year );
        			$activity['end']['timestamp'] = mktime( $end[6], $end[7], 0, $month, $day, $year );
        			
                    $title = (array) $item->title;
                    $title = $title[0];
                    /* Replace a-zA-ZæøåÆØÅéèüÉÈÜ with \p{L} when the server supports unicode in PCRE regex : ) */
        			if ( preg_match( '/([a-zA-ZæøåÆØÅéèüÉÈÜ,\-_ ]*)( \[(.*)\])?: (.*) (\(?)(Ansv. | Ansv. |Ansv: |Ansv |Ansvarlig: )([a-zA-ZæøåÆØÅéèüÉÈÜ,\- ]*)(\)?)/',
        			        $title, $matches ) )
        			{
            			$activity['title'] = rtrim( $matches[4], " ;" );
            			$activity['lab'] = $matches[1];
            			$activity['rig'] = $matches[3];
            			$activity['incharge'] = $matches[7];
            		}
            		else
            		{
            		    $activity['title'] = $title;
            		}
            		/*
            		 * Create a unique ID based on activity data and use it as the array key to avoid duplicates
            		 */
            		$activity['uid'] = sha1( serialize( $activity ) );
        		    $activities[$activity['uid']] = $activity;
        		    /*
        		     * Add one day to current reference time
        		     */
                    $currentTime += 24 * 60 * 60;
        		}
        		while ( date( 'Y-m-d', $currentTime - 24 * 60 * 60 ) != date( 'Y-m-d', $endTime ) );
    		}
    	}
    	/*
    	 * Update table
    	 */
    //	TeamPlayers::$db->query( "TRUNCATE TABLE `ActivityCalendarSharepointRecords`" );
    	$sql = "REPLACE INTO `ActivityCalendarSharepointRecords` ( `uid`, `calendar`, `title`, `lab`, `rig`, `start`, `end`, `incharge`, `timestamp` ) VALUES ";
    	$activity = array();
    	foreach ( $activities as $activity )
    	{
    	    $sql .= "( '{$activity['uid']}',
    	            '{$activity['calendar']}',
    	            '{$activity['title']}',
    	            '{$activity['lab']}',
    	            '{$activity['rig']}',
    	            FROM_UNIXTIME( {$activity['start']['timestamp']} ),
    	            FROM_UNIXTIME( {$activity['end']['timestamp']} ),
    	            '{$activity['incharge']}',
    	            NOW() ), ";
    	}
    	$sql = rtrim( $sql, ", " );
    	TeamPlayers::$db->query( $sql );
    	echo TeamPlayers::$db->error;
    	return true;
	}
	/**
	 * Fetches activities matching the criteria from mysql table, or all activities by default
	 *
     * @param       string $fromDate        Fetch records starting on the specified date or later (ISO 8601 / MySQL format)
     * @param       string $toDate          Fetch records ending on the specified date or earlier (ISO 8601 / MySQL format)
	 * @param       string $relativeDate    May be specified instead of $fromDate and $toDate. Accepted values: today, tomorrow
	 * @param		string $calendar        Filter by calendar (exact match, comma separated list of calendars allowed)
	 * @param       string $lab             Filter by lab (exact match)
	 * @param       string $rig             Filter by rig (exact match)
	 * @param       string $title           Filter by title (partial match)
	 * @param       string $fulltext        Match the specified string against text columns
	 * @param       mixed $orderBy          Name of column(s) to order results by. String or array of strings. Event start date by default.
	 * @param       string $orderDir        Direction in which to order results. ASC or DESC, ASC by default
	 * @return		bool
	 * @access		public
	 */
	public function fetchActivities( $fromDate = "", $toDate = "", $relativeDate = "", $calendar = "", $lab = "", $rig = "", $title = "",
	        $fulltext = "", $orderBy = "start", $orderDir = "ASC" )
	{
	    /*
	     * Sanitize input data and convert dates for mysql
	     */
	    $fromDate    = TeamPlayers::$db->real_escape_string( $fromDate );
	    $toDate      = TeamPlayers::$db->real_escape_string( $toDate );
	    $lab         = TeamPlayers::$db->real_escape_string( $lab );
	    $rig         = TeamPlayers::$db->real_escape_string( $rig );
	    $title       = TeamPlayers::$db->real_escape_string( $title );
	    $fulltext    = TeamPlayers::$db->real_escape_string( $fulltext );
	    if ( ! empty( $calendar ) )
	    {
    	    $calendarsArray = explode( ",", $calendar );
    	    $calendar = "";
    	    $calendars = "";
    	    foreach ( $calendarsArray as $calendar )
    	    {
    	        $calendar = TeamPlayers::$db->real_escape_string( $calendar );
    	        $calendars .= "'{$calendar}', ";
    	    }
    	    $calendars = rtrim( $calendars, ", " );
    	}
	    if ( strtoupper( $orderDir ) != "DESC" )
	    {
	        $orderDir = "ASC";
	    }
	    if ( ! empty( $relativeDate ) )
	    {
	        $now = time();
	        if ( $relativeDate == "today" )
	        {
	            $time = $now;
	        }
	        else if ( $relativeDate == "tomorrow" )
	        {
	            $time = $now + 60 * 60 * 24;
	        }
	        $fromDate = date( 'Y-m-d H:i:s', mktime( 0, 0, 0, date( 'm', $time ), date( 'd', $time ), date( 'Y', $time ) ) );
	        $toDate = date( 'Y-m-d H:i:s', mktime( 23, 59, 59, date( 'm', $time ), date( 'd', $time ), date( 'Y', $time ) ) );
	    }
	    /*
	     * Generate SQL query
	     */
		$sql = "SELECT
	                `calendar`,
	                `title`,
	                `lab`,
	                `rig`,
	                UNIX_TIMESTAMP( `start` ) AS `start`,
	                UNIX_TIMESTAMP( `end` ) AS `end`,
	                `incharge`
	            FROM
	                `ActivityCalendarSharepointRecords`
	            WHERE 1 ";
		if ( ! empty( $calendar ) )
		{
		    $sql .= "AND `calendar` IN ( {$calendars} ) ";
		}
		if ( ! empty( $lab ) )
		{
		    $sql .= "AND `lab` = '{$lab}' ";
		}
		if ( ! empty( $rig ) )
		{
		    $sql .= "AND `rig` = '{$rig}' ";
		}
		if ( ! empty( $title ) )
		{
		    $sql .= "AND `title` LIKE( '%{$title}%' ) ";
		}
		if ( ! empty( $fulltext ) )
		{
		    $sql .= "AND MATCH ( `calendar`, `title`, `lab`, `rig`, `incharge` ) AGAINST ( '{$fulltext}' IN BOOLEAN MODE ) ";
		}
		if ( ! empty( $fromDate ) )
		{
		    if ( strlen( $fromDate ) < 16 )
		    {
		        $fromDate .= ' 00:00';
		    }
		    $sql .= "AND `start` >= '{$fromDate}' ";
		}
		if ( ! empty( $toDate ) )
		{
		    if ( strlen( $toDate ) < 16 )
		    {
		        $toDate .= ' 23:59';
		    }
		    $sql .= "AND `end` <= '{$toDate}' ";
		}
		$orderBySql = "ORDER BY ";
		if ( is_array( $orderBy ) )
		{
		    foreach ( $orderBy as $string )
		    {
		        $orderBySql .= "`{$string}` {$orderDir}, ";
		    }
		    $orderBySql = rtrim( $orderBySql, ", " );
		}
		else
		{
		    $orderBySql .= "`{$orderBy}` {$orderDir}";
		}
		$sql .= $orderBySql;
		/*
		 * Fetch activities
		 */
		$activities = array();
		if ( $result = TeamPlayers::$db->query( $sql ) )
		{
		    while ( $activity = $result->fetch_assoc() )
		    {
		        $start = $activity['start'];
		        $end = $activity['end'];
		        $activity['start'] = array();
		        $activity['end'] = array();
		        $activity['start']['timestamp'] = $start;
		        $activity['end']['timestamp'] = $end;
		        if ( $activity['start']['timestamp'] > time() )
		        {
		            $activity['relativeTime'] = self::relativeTime( $activity['start']['timestamp'] );
		        }
		        else
		        {
		            $activity['relativeTime'] = self::relativeTime( $activity['end']['timestamp'] );
		        }
		        if ( date( 'H:i', $activity['start']['timestamp'] ) == '00:00' &&  date( 'H:i', $activity['end']['timestamp'] ) == '23:59' )
		        {
		            $activity['all-day'] = true;
		        }
		        else
		        {
		            $activity['all-day'] = false;
		        }
		        $activity['allday'] = $activity['all-day']; /* Fix for Smarty */
		        if ( $activity['start']['timestamp'] < time() && $activity['end']['timestamp'] > time() )
		        {
		            $activity['ongoing'] = true;
		        }
		        else
		        {
		            $activity['ongoing'] = false;
		        }
		        $activities[] = $activity;
		    }
		}
		$this->activities = $activities;
	}
	/**
	 * Adds or replaces a calendar. If a calendar of the specified name already exists, it will be overwritten.
	 *
	 * @param		string $name
	 * @param       string $feedURL  URL to Sharepoint calendar RSS feed
	 * @return		bool
	 * @access		public
	 */
	public function setCalendar( $name, $feedURL )
	{
		$this->calendars[$name] = $feedURL;
		return TeamPlayers::$db->query( "REPLACE INTO `ActivityCalendarCalendars` SET `name` = '{$name}', `feedURL` = '{$feedURL}'" );
	}
	/**
	 * Removes a calendar. Returns false if the calendar doesn't exist or true if it was removed.
	 *
	 * @param		string $name
	 * @return		bool
	 * @access		public
	 */
	public function removeCalendar( $name )
	{
		if ( isset( $this->calendars[$name] ) )
		{
		    unset( $this->calendars[$name] );
		    TeamPlayers::$db->query( "DELETE FROM `ActivityCalendarCalendars` WHERE `name` = '{$name}'" );
		    return true;
		}
		else
		{
		    return false;
		}
	}
	/**
	 * Returns an array containing the names of the registered calendars
	 *
	 * @return		array
	 * @access		public
	 */
	public function getCalendarNames()
	{
		return array_keys( $this->calendars );
	}
	/**
	* Renders a HTML listing of calendar events that were fetched with fetchActivities()
	*
	* @param        string $type
	* @return		string
	* @access		public
	* @static
	*/
	public function renderEventList()
	{
		$activities = $this->activities;
		/*
		 * Generate HTML
		 */
		$html  = '<div class="event-listing">';
		if ( ! empty( $activities ) )
		{
    		$html .= '<ul class="activities">';
    		foreach ( $activities as $activity )
    		{
    		    $startTime = date( 'H:i', $activity['start']['timestamp'] );
    		    $endTime = date( "H:i", $activity['end']['timestamp'] );
    		    $html .= '<li>';
    		    $html .= '<span class="timespan">';
    		    if ( $activity['all-day'] )
    		    {
    		        $html .= 'Hele dagen';
    		    }
    		    else
    		    {
    		        $html .= "{$startTime}&nbsp;-&nbsp;{$endTime}";
    		    }
    		    $html .= '</span> <span class="note">';
    		    if ( $activity['ongoing'] )
    		    {
    		        $html .= '(pågår nå)';
    		    }
    		    else
    		    {
    		        $html .= '(' . $activity['relativeTime'] . ')';
    		    }
    		    $html .= <<<HTML
</span><br />
    {$activity['lab']}: {$activity['title']}<br />
    <span class="incharge">Ansvarlig: {$activity['incharge']}</span>
    </li>
HTML;
    		}
    		$html .= '</ul>';
    	}
    	else
    	{
    	    $html .= '<p class="no-activities">Ingen aktiviteter.</p>';
    	}
    	$html .= '</div>';
		return $html;
	}
	/**
	* Renders a HTML table of calendar events that were fetched with fetchActivities()
	*
	* @return		string
	* @access		public
	* @static
	*/
	public function renderEventTable()
	{
		$activities = $this->activities;
		/*
		 * Generate HTML
		 */
		if ( ! empty( $activities ) )
		{
		    TeamPlayers::$smarty->assign( 'activities', $activities );
		    $html = TeamPlayers::$smarty->fetch( 'calendar/activities-table.tpl' );
    	}
    	else
    	{
    	    $html = '<p class="no-activities">Ingen aktiviteter.</p>';
    	}
		return $html;
	}
	/**
	 * Outputs an event creation form if requested
	 *
	 * @return		void
	 * @access		public
	 */
	public function eventCreationFormRequest()
	{
		if ( ! ( isset( $_REQUEST['eventCreationForm'] ) && $_REQUEST['eventCreationForm'] == true ) )
		{
		    return;
		}
		echo TeamPlayers::$smarty->fetch( 'calendar/calendar-activity-registration-form.tpl' );
		exit;
	}
    /**
	 * Checks POST for event creation form parameters and eventually handles the form
	 *
	 * @return		void
	 * @access		public
	 */
	public function eventCreationRequest()
	{
	    ini_set( "display_errors", false );
		if ( ! ( isset( $_REQUEST['createEvent'] ) && $_REQUEST['createEvent'] == true ) )
		{
		    return;
		}
		if ( ! TeamPlayers::$ac->authenticated )
		{
		    header( "Content-type: text/plain; charset=utf-8" );
		    echo json_encode( array(
		            "status" => "error",
		            "message" => "Du må være innlogget for å opprette aktiviteter. Vennligst logg inn med skjemaet øverst på siden.",
		            "invalid" => array() ) );
		    exit;
		}
		/*
		 * Input data array (for testing)
		 */
		/*
		$_REQUEST = array(
		    'calendar'       => 'Martin',
		    'title'          => 'Testdetonasjon',
		    'lab'            => 'Kjernefysisk lab',
		    'rig'            => 'Kjernefysisk detonasjonsrigg',
		    'incharge'       => 'Leo Valen',
		    'notes'          => 'Dette er bare en test, altså.',
		    'startDate'      => '2010-03-02',
		    'startTime'      => '10:00',
		    'endDate'        => '2010-03-05',
		    'endTime'        => '14:00'
		);
		*/
		
		$fields = array( 'calendar', 'lab', 'rig', 'title', 'incharge', 'notes', 'startDate', 'startTime', 'endDate', 'endTime' );
		$empty = array();
		$invalid = array();
		$data = array();
		$startDatetimeComponents = array();
		$endDatetimeComponents = array();
		/*
		 * Validate form input
		 */
		foreach ( $fields as & $field )
		{
		    if ( isset( $_REQUEST[$field] ) && ! empty( $_REQUEST[$field] ) )
		    {
		        $data[$field] = $_REQUEST[$field];
		    }
		    else
		    {
		        $data[$field] = '';
		        $empty[] = $field;
		    }
		}
		/*
		 * Field specific validation
		 */
		unset( $field );
		foreach ( $fields as & $field )
		{
		    if ( empty( $data[$field] ) )
		    {
		        continue;
		    }
		    if ( $field == 'calendar' )
		    {
		        if ( ! isset( $this->calendars[$data[$field]] ) )
		        {
		            $invalid[] = $field;
		        }
		    }
		    if ( $field == 'lab' )
		    {
		        /*
		         * @todo
		         * Check if lab exists
		         */
		    }
    		if ( $field == 'rig' )
    		{
    		    /*
    		     * @todo
    		     * Check if rig exists
    		     */
    		}
    		if ( $field == 'startDate' || $field == 'endDate' )
    		{
    		    if ( empty( $data[$field] ) || ! preg_match( '/([0-9]{2})\.([0-9]{2})\.([0-9]{4})/', $data[$field], ${$field . 'Match'} ) )
    		    {
    		        $invalid[] = $field;
    		    }
    		}
    		if ( $field == 'startTime' || $field == 'endTime' )
    		{
    		    if ( empty( $data[$field] ) || ! preg_match( '/([0-9]{2}):([0-9]{2})/', $data[$field], ${$field . 'Match'} ) )
    		    {
    		        $invalid[] = $field;
    		    }
    		}
		}
		/*
		 * @todo
		 * Check if this activity is compatible with existing activities
		 */
		
		/*
		 * Check if all fields validated successfully and provide feedback else
		 */
		foreach ( $empty as $field )
		{
		    /*
		     * Fields other than 'notes' and 'rig' should be marked as invalid if empty
		     */
		    if ( $field != 'notes' && $field != 'rig' )
		    {
		        $invalid[] = $field;
		    }
		}
		if ( ! empty( $invalid ) )
		{
		    header( "Content-type: text/plain; charset=utf-8" );
		    echo json_encode( array(
		            "status" => "error",
		            "message" => "Det var en eller flere feil i utfyllingen. Rett de markerte feltene og prøv på nytt.",
		            "invalid" => $invalid ) );
		    exit;
		}
		
		$data['user'] = TeamPlayers::$ac->user;
		$data['creator'] = TeamPlayers::$ac->name;
		/*
		 * Compile start and end datetime component arrays
		 */
		if ( isset( $startDateMatch ) )
		{
		    $startDatetimeComponents['year'] = $startDateMatch[3];
		    $startDatetimeComponents['month'] = $startDateMatch[2];
		    $startDatetimeComponents['date'] = $startDateMatch[1];
		}
		if ( isset( $endDateMatch ) )
		{
		    $endDatetimeComponents['year'] = $endDateMatch[3];
		    $endDatetimeComponents['month'] = $endDateMatch[2];
		    $endDatetimeComponents['date'] = $endDateMatch[1];
		}
		if ( isset( $startTimeMatch ) )
		{
		    $startDatetimeComponents['hour'] = $startTimeMatch[1];
		    $startDatetimeComponents['minute'] = $startTimeMatch[2];
		}
		if ( isset( $endTimeMatch ) )
		{
		    $endDatetimeComponents['hour'] = $endTimeMatch[1];
		    $endDatetimeComponents['minute'] = $endTimeMatch[2];
		}
		
		/*
		 * Create vCal calendar event 
		 */
		$v = new vcalendar();
		$v->setConfig( 'unique_id', 'TeamPlayers.no' );
		$v->setProperty( "X-WR-TIMEZONE", "Europe/Oslo" );
		$e = new vevent();
		$start = $startDatetimeComponents;
		$end = $endDatetimeComponents;
		$e->setProperty( 'summary', "{$data['lab']} [{$data['rig']}]: {$data['title']} (Ansvarlig: {$data['incharge']})" );
		$e->setProperty( 'dtstart', $start['year'], $start['month'], $start['date'], $start['hour'], $start['minute'], 00 );
		$e->setProperty( 'dtend', $end['year'], $end['month'], $end['date'], $end['hour'], $end['minute'], 00 );
		$e->setProperty( 'description', $data['notes'] );
		$e->setProperty( 'location', $data['lab'] ); 
	//	$v->setProperty( 'X-WR-CALNAME' , 'Work' );
		$v->addComponent( $e );		
		/*
		 * Write temporary iCal file
		 */
		$uuid = TeamPlayers::uuid();
		$filename = TeamPlayersTemporaryFileDirectory . "/event-{$uuid}.ics";
		$handle = fopen( $filename, "w" );
		fwrite( $handle, $v->createCalendar() );
		fclose( $handle );
		/*
		 * Format full date/time
		 */
		$data['startUnixtime'] = mktime( $start['hour'], $start['minute'], 0, $start['month'], $start['date'], $start['year'] );
		$data['endUnixtime'] = mktime( $end['hour'], $end['minute'], 0, $end['month'], $end['date'], $end['year'] );
		$data['start'] = date( 'Y-m-d H:i:s', $data['startUnixtime']  );
		$data['end'] = date( 'Y-m-d H:i:s', $data['endUnixtime']  );
		$data['startNorwegianDate'] = date( 'd.m.Y', $data['startUnixtime'] );
		$data['endNorwegianDate'] = date( 'd.m.Y', $data['endUnixtime'] );
		/*
		 * Fetch email notification recipients
		 */
		$recipients = array();
		if ( $rows = TeamPlayers::$db->selectAssoc( "SELECT `name`, `email` FROM `ActivityCalendarEventRecipients`" ) )
		{
		    foreach ( $rows as $row )
		    {
		        $recipients[$row['email']] = $row['name'];
		    }
		}
		/*
		 * Send email with attached iCal file
		 */
		if ( ! empty( $data['notes'] ) )
		{
		    $notes = "Merknader: " . $data['notes'];
		}
		$messageText = <<<EMAIL
{$data['creator']} har opprettet en ny aktivitet. Kalenderoppføringen er vedlagt.

{$notes}

Kalender:\t\t{$data['calendar']}
Beskrivelse:\t\t{$data['title']}
Lab:\t\t\t{$data['lab']}
Rigg:\t\t\t{$data['rig']}
Startdato:\t\t{$data['startNorwegianDate']}
Sluttdato:\t\t{$data['endNorwegianDate']}
Tidspunkt:\t\t{$data['startTime']}-{$data['endTime']}


EMAIL;
		$transport = Swift_SmtpTransport::newInstance( TeamPlayersSMTPHost, TeamPlayersSMTPPort )
		        ->setUsername( TeamPlayersSMTPUsername )
		        ->setPassword( TeamPlayersSMTPPassword );
		$mailer = Swift_Mailer::newInstance($transport);
		$message = Swift_Message::newInstance()
		        ->setSubject( "Ny aktivitet ({$data['calendar']}) - {$data['title']}" )
			    ->setFrom(array('robot@TeamPlayers.no' => 'TeamPlayers'))
			    ->setTo( $recipients )
		        ->setBody( $messageText )
		        ->attach( Swift_Attachment::fromPath( $filename ) );
		$result = $mailer->send( $message );
		/*
		 * Delete temporary iCal file
		 */
		unlink( $filename );
		/*
		 * Sanitize form input for database insertion
		 */
		foreach ( $data as & $value )
		{
		    $value = TeamPlayers::$db->real_escape_string( $value );
		}
		/*
		 * Insert creation request into table
		 */
		$sql = "INSERT INTO
		            `ActivityCalendarEventCreationRequest`
		        SET
		            `user`        = '{$data['user']}',
		            `calendar`    = '{$data['calendar']}',
		            `title`       = '{$data['title']}',
		            `lab`         = '{$data['lab']}',
		            `rig`         = '{$data['rig']}',
		            `incharge`    = '{$data['incharge']}',
		            `notes`       = '{$data['notes']}',
		            `start`       = '{$data['start']}',
		            `end`         = '{$data['end']}',
		            `timestamp`   = NOW()";
		TeamPlayers::$db->query( $sql );
		/*
		 * Success
		 */
		header( "Content-type: text/plain; charset=utf-8" );
		echo json_encode( array(
		        "status" => "success",
		        "message" => "",
		        "invalid" => array() ) );
		exit;
	}
	/**
	* Checks GET for search parameters and handles an eventual search request
	*
	* 
	* @return		void
	* @access		protected
	* @static
	*/
	protected function searchRequest( )
	{
		if ( ! ( isset( $_GET['search'] ) && $_GET['search'] == true ) )
		{
		    return;
		}
		$fromDate = "";
		$toDate = "";
		$relativeDate = "";
		$calendar = "";
		$lab = "";
		$rig = "";
		$title = "";
		$fulltext = "";
		$orderBy = "start";
		$orderDir = "ASC";
		if ( isset( $_GET['fromDate'] ) ) $fromDate = $_GET['fromDate'];
		if ( isset( $_GET['toDate'] ) ) $toDate = $_GET['toDate'];
		if ( isset( $_GET['relativeDate'] ) ) $relativeDate = $_GET['relativeDate'];
		if ( isset( $_GET['calendar'] ) ) $calendar = $_GET['calendar'];
		if ( isset( $_GET['lab'] ) ) $lab = $_GET['lab'];
		if ( isset( $_GET['rig'] ) ) $rig = $_GET['rig'];
		if ( isset( $_GET['title'] ) ) $title = $_GET['title'];
		if ( isset( $_GET['fulltext'] ) ) $fulltext = $_GET['fulltext'];
		if ( isset( $_GET['orderBy'] ) ) $orderBy = $_GET['orderBy'];
		if ( isset( $_GET['orderDir'] ) ) $orderDir = $_GET['orderDir'];
		/*
		 * Convert Norwegian dates to ISO format
		 */
		if ( preg_match( '/([0-9]{2})\.([0-9]{2})\.([0-9]{4})/', $fromDate, $matches ) )
		{
		    $fromDate = $matches[3] . '-' . $matches[2] . '-' . $matches[1];
		}
		if ( preg_match( '/([0-9]{2})\.([0-9]{2})\.([0-9]{4})/', $toDate, $matches ) )
		{
		    $toDate = $matches[3] . '-' . $matches[2] . '-' . $matches[1];
		}
		/*
		 * Fetch activities and render output
		 */
		$this->fetchActivities( $fromDate, $toDate, $relativeDate, $calendar, $lab, $rig, $title, $fulltext, $orderBy, $orderDir );
		if ( isset( $_GET['format'] ) && $_GET['format'] == 'html' )
		{
		    header( "Content-type: text/html; charset=utf-8" );
		    if ( isset( $_GET['listingType'] ) && $_GET['listingType'] == 'table' )
		    {
		        echo $this->renderEventTable();
		    }
		    else
		    {
		        echo $this->renderEventList();
		    }
		}
		else
		{
		    header( "Content-type: text/plain" );
		    echo json_encode( $this->activities );
		}
		exit;
	}
	/**
	* Returns a time difference as a string using a sensible unit (e.g. "10 seconds ago", "in 4 days")
	* (In Norwegian)
	*
	* @todo         Make it locale aware
	* @param		$time
	* @param		$now  Reference time, defaults to now
	* @return		array
	* @access		public
	* @static
	*/
	public static function relativeTime( $time, $now = false )
	{
		$time = (int) $time;
		$current = $now ? $now : time();
		$shift = $current - $time;
	    $future = false;
	    if ( $shift < 0 )
	    {
	        $future = true;
	        $shift = -$shift;
	    }
		if ( $shift < 60 )
		{
			$diff = $shift;
			$term = "sekund";
		}
		else if ( $shift < 3600 )
		{
			$diff = round( $shift / 60 );
			$term = "minutt";
		}
		else if ( $shift < 64800 )
		{
			$diff = round( $shift / 60 / 60 );
			$term = "time";
		}
		else if ( $shift < 1944000 )
		{
			$diff = round( $shift / 60 / 60 / 24 );
			$term = "dag";
		}
		else
		{
		    $diff = round( $shift / 60 / 60 / 24 / 30 );
		    $term = "måned";
		}
		if ( $diff != 1 ) 
	    {
	        if ( $term[strlen( $term ) - 1] == 'e' )
	        {
	            $term .= "r";
	        }
	        else
	        {
	            $term .= "er";
	        }
	    }
	    if ( $future )
	    {
	        return "om $diff $term";
	    }
	    else
	    {
	        return "$diff $term siden";
	    }
	}
}
?>